###############################################################################
#
# SeqUtils module
# Developed by Rafael Garabato and Marcos Oviedo
###############################################################################
#
# FuDePAN
# Copyright (C) 2009, FuDePAN
#
#   SeqUtils.pm is part of sequtils.
#
#   sequtils is free software: you can redistribute it and/or modify
#   it under the terms of the GNU General Public License as published by
#   the Free Software Foundation, either version 3 of the License, or
#   (at your option) any later version.
#
#   sequtils is distributed in the hope that it will be useful,
#   but WITHOUT ANY WARRANTY; without even the implied warranty of
#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#   GNU General Public License for more details.
#
#   You should have received a copy of the GNU General Public License
#   along with sequtils.  If not, see <http://www.gnu.org/licenses/>.
#
###############################################################################
package BioUtils::SeqUtils;
use strict;
use warnings;
use Cwd;
use LWP::Simple;
use LWP::UserAgent;
use XML::Parser;
use XML::Simple;
use Data::Dumper;

require 5;
require Exporter;

#current version
use vars qw($VERSION);
$VERSION = '0.01';

#Meaningful definitions
use constant ZFALSE => 0;
use constant ZTRUE => 1;
use constant TRIPLETS_LENGTH => 3;

#Behavior variables
our $verbose;

#functions to be exported
@BioUtils::SeqUtils::ISA=qw(Exporter);
@BioUtils::SeqUtils::EXPORT=qw( fudepan_print randomizeSequence evaluate_cmd http_get is_word_present 
					  get_search_id get_eutil_xml_data print_esummary_xml_file get_efetch_sequence 
					  get_efetch_sequence_with_gene generate_translation_from_xml  
					  get_efetch_translation save_file delete_files calculate_translation 
					  are_translations_compatible are_aminoacids_compatible get_working_dir directory_exists 
					  create_set_directory cache_get_search_id cache_update_search_id cache_get_eutil_xml_data
					  fuzzy_get_efetch_sequence_with_gene set_verbosity );

#Worktables
my %rnaCodonTable =	
(
	"ttt"=> "F",   "tct"=> "S", "tat"=> "Y",   "tgt"=> "C",
	"ttc"=> "F",   "tcc"=> "S", "tac"=> "Y",   "tgc"=> "C",
	"tta"=> "L",   "tca"=> "S", "taa"=> "TER", "tga"=> "TER",
	"ttg"=> "L",   "tcg"=> "S", "tag"=> "TER", "tgg"=> "W",
	"ctt"=> "L",   "cct"=> "P", "cat"=> "H",   "cgt"=> "R",
	"ctc"=> "L",   "ccc"=> "P", "cac"=> "H",   "cgc"=> "R",
	"cta"=> "L",   "cca"=> "P", "caa"=> "Q",   "cga"=> "R",
	"ctg"=> "L",   "ccg"=> "P", "cag"=> "Q",   "cgg"=> "R",
	"att"=> "I",   "act"=> "T", "aat"=> "N",   "agt"=> "S",
	"atc"=> "I",   "acc"=> "T", "aac"=> "N",   "agc"=> "S",
	"ata"=> "I",   "aca"=> "T", "aaa"=> "K",   "aga"=> "R",
	"atg"=> "M",   "acg"=> "T", "aag"=> "K",   "agg"=> "R",
	"gtt"=> "V",   "gct"=> "A", "gat"=> "D",   "ggt"=> "G",
	"gtc"=> "V",   "gcc"=> "A", "gac"=> "D",   "ggc"=> "G",
	"gta"=> "V",   "gca"=> "A", "gaa"=> "E",   "gga"=> "G",
	"gtg"=> "V",   "gcg"=> "A", "gag"=> "E",   "ggg"=> "G"
);


#######
# Setter method to verbosity flag
# Parameter: ZTRUE or ZFALSE based on user needs
# Returns: nothing	
#
sub set_verbosity
{
    my $verbosity_flag = shift;

	if ( $verbosity_flag  )
	{
		$verbose = ZTRUE;	
	}
}


#######
# Wrapper print to stdout
# Parameter: input to print
# Returns: nothing	
#
sub fudepan_print
{
    my $string = shift;

	if ( defined($verbose) )
	{
		# flush all output immediately
		$| = 1;	
		print STDERR "[+] $string";
	}
}


#######
# Randomize the elements of a sequence
# Parameter: sequence string
# Returns: randomized sequence
#

sub randomizeSequence
{
    my ($sequence) = @_;
    my $seqLength = length($sequence);
    my $randRange =  $seqLength - 1;
    my $randElem;
    my $randSeq = "";


    my @sequenceArray =split(//, $sequence);

    for (my $i=0; $i < $seqLength; $i++)
    {
        my $range = $randRange-$i;
        $randElem = int(rand($range));
        $randSeq .= $sequenceArray[$randElem];
        splice (@sequenceArray,$randElem,1);
    }
 
    return ($randSeq);

}

			  
#######
# command execution
# Parameter: command to be executed
# Returns: temporal array that contains
#                       the status variable resulted from the execution
#                       one line of the text printed by the command executed
#
sub evaluate_cmd
{
    my $cmd = shift;
    my $status;
    my @ret_array;

    #waiting some time to sync, execute command and save status
    sleep(1);
    @ret_array = `$cmd`;
    $status = $?;

    return ($status, \@ret_array);
}

#######
# Trivial HTTP get with timeou
# Parameter: URL to consult, timeout to use and ptr to the response
# Returns: True or False according the Results of the Operation
#
sub http_get 
{
    my ($url, $timeout, $ptrResponse ) = @_;
    my $status = ZFALSE;
    my $browser;
    my $request;
    my $response;
    my $htmlResponse;

    #Setting the browser up
    $browser = LWP::UserAgent->new;

    #Setting the timeout
    $browser->timeout($timeout);

    #Setting the UserAgent
    $browser->agent('FudepanONG/1.0');

    #Querying CGI to obtain raw data
    $request = HTTP::Request->new('GET', $url);

    #Fetching the response ptr
    $response = $browser->request($request);
	
	#Check if the request was successful
	if( $response->is_success )
	{
	    #Grabbing out the response
	    $htmlResponse = $response->content;

		#Check the HTML response
	    if ( defined($htmlResponse) )
	    {
	        $$ptrResponse = $htmlResponse;
	        $status = ZTRUE;       
	    }	
	} 
	else
	{
		fudepan_print("There was a problem while querying the URL: $url\n");
		fudepan_print("The problem was: ". $response->status_line ."\n");
	}


    return $status;
}



#######
# Find the ocurrence of a word inside of an array
# Parameter: String to look into, string to look for
# Returns: True or False according the Results of the Operation
#
sub is_word_present
{
	my ($stringToLookInto, $wordToLookFor) = @_;
    my $status = ZFALSE;
	my $item;
	
	#splitting the provided string 
	foreach $item ( split(/\s/,$stringToLookInto) )
	{
		#look for the word provided in a case insensitive way 
		if ( $item =~ /^$wordToLookFor$/i )			
		{
			#word found
			$status = ZTRUE;			
		}
	}

	return $status;
}



#######
# get the SearchID to use on the following calls
# Parameter: URL to consult, Secuence to look for, ptr to store the number of ocurrences and timeout for HTTP queries 
#            ptr to store the searchID
# Returns: True or False according the Results of the Operation
#
sub get_search_id 
{
    my ($esearchURL, $sequenceID, $ptrNumberOcurrences, $ptrSearchID, $timeout ) = @_;
    my $status = ZFALSE;
   	my $rawResult;
	my $xmlObject;
	my $xmlData;
	my $numberOcurrences;
	my $searchID;

	#Querying Esearch utility using the provided sequence
	if ( http_get($esearchURL . $sequenceID, $timeout, \$rawResult ) and defined($rawResult) )
	{
		# create XML object
		$xmlObject = new XML::Simple;

		# parse XML data
		$xmlData = $xmlObject->XMLin($rawResult);

		if ( defined($xmlData) )
		{
			#Grabbing out the number of ocurrences
			$$ptrNumberOcurrences = $xmlData->{Count};

			if ($$ptrNumberOcurrences eq 1 )
			{
				#Grabbing out the searchID
				$$ptrSearchID = $xmlData->{IdList}->{Id};

				$status = ZTRUE;		
			} 
		}
		else
		{
			fudepan_print("Unitialized XML was found while parsing SearchID\n");
		}
	}
	else
	{
		fudepan_print("HTML data can not be obtained while parsing SearchID\n");
	}

	return $status;
} 


#######
# get rawXML from the passed operation URL
# Parameter: CGI URL for the  operation, SearchID to look for, ptr to Store the obtained XML file and query timeout
# Returns: True or False according the Results of the Operation
#
sub get_eutil_xml_data
{
    my ($operationURL, $searchID, $ptrRawXML, $timeout ) = @_;
    my $status = ZFALSE;
   	my $rawResult;
	my $queryResponse;

	#Querying CGI to obtain raw data	
	if ( http_get($operationURL . $searchID, $timeout, \$queryResponse) and defined($queryResponse) )
	{
		#Grabbing out the results
		$$ptrRawXML = $queryResponse;	
		$status = ZTRUE;		
	}
	else
	{
		fudepan_print("XML data can not be obtained\n");
	}


	return $status;
}


#######
# Print Data obtained from Esummary 
# Parameter: Raw XML data
# Returns: True or False according the Results of the Operation
#
sub print_esummary_xml_file
{
	my $rawData = shift;
    my $status = ZFALSE;
	my $xmlObject;
	my $xmlData;

	#create XML object
	$xmlObject = new XML::Simple;

	#parse XML data
	$xmlData = $xmlObject->XMLin($rawData);

	# just for debugging purposes
	#print Dumper($xmlData) . "\n";

	if ( defined($xmlData) )
	{
		print "ID: ".$xmlData->{DocSum}->{Id}."\n";
		print "Title: ".$xmlData->{DocSum}->{Item}[1]{content}."\n";
		print "Extra: ".$xmlData->{DocSum}->{Item}[2]{content}."\n";
		print "SearchID: ".$xmlData->{DocSum}->{Item}[3]{content}."\n";
		print "TaxId: ".$xmlData->{DocSum}->{Item}[7]{content}."\n";
		print "Length: ".$xmlData->{DocSum}->{Item}[8]{content}."\n";
		print "Status: ".$xmlData->{DocSum}->{Item}[9]{content}."\n";

		$status = ZTRUE;
	}
	
	return $status;	
}



#######
# Print Sequence data obtained from Efetch 
# Parameter: Raw XML data
# Returns: True or False according the Results of the Operation
#
sub get_efetch_sequence
{
	my ($rawData, $ptrSequence) = @_;
    my $status = ZFALSE;
	my $xmlObject;
	my $xmlData;
	my $sequence;

	#create XML object
	$xmlObject = new XML::Simple;

	#parse XML data
	$xmlData = $xmlObject->XMLin($rawData);

	# just for debugging purposes
	#print Dumper($xmlData) . "\n";

	if ( defined($rawData) )
	{

		if ( defined($xmlData) )
		{
			#Not Assuming that the needed XML tags are in the fetched XML
			if ( defined ( $xmlData->{'GBSeq'}->{'GBSeq_sequence'} ) ) 
			{ 
				#Grabbing out the sequence from the XML data
				$sequence = $xmlData->{'GBSeq'}->{'GBSeq_sequence'};

				#setting sequence ptr
				$$ptrSequence = $sequence;
				$status = ZTRUE;
			}
		}
		else
		{
			fudepan_print("Unitialized XML was found while parsing XML Data\n");
		}
	}
	else
	{
		fudepan_print("HTML data can not be obtained while parsing XML Data\n");
	}

	return $status;	
}



#######
# Get gene sequence data obtained from Efetch 
# Parameter: Raw XML data, genoma sequence, gene to look for and ptr to store the sequence subset
# Returns: True or False according the Results of the Operation
#
sub get_efetch_sequence_with_gene
{
	my ($rawData, $sequence, $geneString, $ptrGeneSequence) = @_;
    my $status = ZFALSE;
	my $xmlObject;
	my $xmlData;
	my $sequenceIntervalFrom;
	my $sequenceIntervalTo;
	my $gbFeatureArray;
	my $gbQualifierArray;
	my $item;
	my $gbItem;

	#create XML object
	$xmlObject = new XML::Simple;

	#parse XML data
	$xmlData = $xmlObject->XMLin($rawData);

	# just for debugging purposes
	#print Dumper($xmlData) . "\n";

	if ( defined($xmlData) and defined($geneString) )
	{
		#Not assuming that the needed XML tags are in the fetched XML
		#Getting out the gene intervals	on the XML data					  
		if( defined( $xmlData->{'GBSeq'}->{'GBSeq_feature-table'}->{'GBFeature'} ) )
		{
			$gbFeatureArray = $xmlData->{'GBSeq'}->{'GBSeq_feature-table'}->{'GBFeature'};

			foreach $item (@$gbFeatureArray)
			{
				if ( defined $item->{'GBFeature_key'} and 
					 $item->{'GBFeature_key'} eq "CDS" and
					 not defined($sequenceIntervalFrom) and
					 not defined($sequenceIntervalTo) and
					 defined ($item->{'GBFeature_quals'}{'GBQualifier'})  )
				{		
					#If GBQualifier is a hash and GBQualifier_value is equal to the gene looked 
					#save out the intervales to the sequence
					if( $item->{'GBFeature_quals'}{'GBQualifier'} =~ /hash/i and
				    	defined ( $item->{'GBFeature_quals'}{'GBQualifier'}{'GBQualifier_value'} ) and
#				    	$item->{'GBFeature_quals'}{'GBQualifier'}{'GBQualifier_value'} eq $geneString )
				    	$item->{'GBFeature_quals'}{'GBQualifier'}{'GBQualifier_value'} =~ /^$geneString$/i )
					{
						#saving gene intervals
						$sequenceIntervalFrom = $item->{'GBFeature_intervals'}{'GBInterval'}{'GBInterval_from'} - 1;
						$sequenceIntervalTo = $item->{'GBFeature_intervals'}{'GBInterval'}{'GBInterval_to'};
						
					}
					#If GBQualifier is a array, transverse it looking for the gene value
					elsif( $item->{'GBFeature_quals'}{'GBQualifier'} =~ /array/i )
					{
						$gbQualifierArray = $item->{'GBFeature_quals'}{'GBQualifier'};
						#Transversing array to look for the item
						foreach $gbItem (@$gbQualifierArray)
						{
						  if ( defined ( $gbItem->{'GBQualifier_value'} ) and
#						  		$gbItem->{'GBQualifier_value'} eq $geneString  )  	 
						  		$gbItem->{'GBQualifier_value'} =~ /^$geneString$/i  )  	 
						  {
								#saving gene intervals
								$sequenceIntervalFrom = $item->{'GBFeature_intervals'}{'GBInterval'}{'GBInterval_from'} - 1;
								$sequenceIntervalTo = $item->{'GBFeature_intervals'}{'GBInterval'}{'GBInterval_to'};			
						  }
						}
					}
					else
					{ 
						#Something nasty happens here
						$status = ZFALSE;
					}
					 													
				}

			}		
		}

		#Printing out the sequence gene intervals						  
		if( defined($sequenceIntervalFrom) and defined($sequenceIntervalTo) )
		{			
			$$ptrGeneSequence = substr($sequence, $sequenceIntervalFrom, $sequenceIntervalTo - $sequenceIntervalFrom);
			$status = ZTRUE;
		}
	}

	return $status;	
}




######
# Get gene sequence data obtained from Efetch in a fuzzy way (not absolut string for gene) 
# Parameter: Raw XML data, genoma sequence, gene to look,  ptr to store the sequence subset	and ptr to store gene matched
# Returns: True or False according the Results of the Operation
#
sub fuzzy_get_efetch_sequence_with_gene
{
	my ($rawData, $sequence, $geneString, $ptrGeneSequence, $ptrGeneMatched) = @_;
    my $status = ZFALSE;
	my $xmlObject;
	my $xmlData;
	my $sequenceIntervalFrom;
	my $sequenceIntervalTo;
	my $gbFeatureArray;
	my $gbQualifierArray;
	my $item;
	my $gbItem;

	#create XML object
	$xmlObject = new XML::Simple;

	#parse XML data
	$xmlData = $xmlObject->XMLin($rawData);

	# just for debugging purposes
	#print Dumper($xmlData) . "\n";

	if ( defined($xmlData) and defined($geneString) )
	{
		#Not assuming that the needed XML tags are in the fetched XML
		#Getting out the gene intervals	on the XML data					  
		if( defined( $xmlData->{'GBSeq'}->{'GBSeq_feature-table'}->{'GBFeature'} ) )
		{
			$gbFeatureArray = $xmlData->{'GBSeq'}->{'GBSeq_feature-table'}->{'GBFeature'};

			foreach $item (@$gbFeatureArray)
			{
				if ( defined ($item->{'GBFeature_key'}) and 
					 defined ($item->{'GBFeature_quals'}{'GBQualifier'}) and
					 $item->{'GBFeature_key'} eq "CDS" and
					 not defined($sequenceIntervalFrom) and
					 not defined($sequenceIntervalTo)  )
				{					 
					#If GBQualifier is a hash and GBQualifier_value can be found on the gene looked 
					#save out the intervales to the sequence
					if( $item->{'GBFeature_quals'}{'GBQualifier'} =~ /hash/i and
				    	defined ($item->{'GBFeature_quals'}{'GBQualifier'}{'GBQualifier_value'}) and
						is_word_present( $item->{'GBFeature_quals'}{'GBQualifier'}{'GBQualifier_value'} , $geneString ) )  	 
					{
						#saving gene intervals and matched gene
						$$ptrGeneMatched = $item->{'GBFeature_quals'}{'GBQualifier'}{'GBQualifier_value'};
						$sequenceIntervalFrom = $item->{'GBFeature_intervals'}{'GBInterval'}{'GBInterval_from'} - 1;
						$sequenceIntervalTo = $item->{'GBFeature_intervals'}{'GBInterval'}{'GBInterval_to'};
						
					}
					#If GBQualifier is a array, transverse it looking for the gene value
					elsif( $item->{'GBFeature_quals'}{'GBQualifier'} =~ /array/i )
					{
						$gbQualifierArray = $item->{'GBFeature_quals'}{'GBQualifier'};
						#Transversing array to look for the item
						foreach $gbItem (@$gbQualifierArray)
						{
						  if ( defined ( $gbItem->{'GBQualifier_value'} ) and
#						  		$gbItem->{'GBQualifier_value'} eq $geneString  )
								is_word_present( $gbItem->{'GBQualifier_value'} , $geneString ) )  	   	 
						  {
								#saving gene intervals and matched gene
								$$ptrGeneMatched = $gbItem->{'GBQualifier_value'};
								$sequenceIntervalFrom = $item->{'GBFeature_intervals'}{'GBInterval'}{'GBInterval_from'} - 1;
								$sequenceIntervalTo = $item->{'GBFeature_intervals'}{'GBInterval'}{'GBInterval_to'};			
						  }
						}
					}
					else
					{ 
						#Something nasty happens here
						$status = ZFALSE;
					}
					 													
				}

			}		
		}

		#Printing out the sequence gene intervals						  
		if( defined($sequenceIntervalFrom) and defined($sequenceIntervalTo) )
		{
			$$ptrGeneSequence = substr($sequence, $sequenceIntervalFrom, $sequenceIntervalTo - $sequenceIntervalFrom);
			$status = ZTRUE;
		}
	}

	return $status;	
}




#######
# Get gene translation sequence data obtained from Efetch 
# Parameter: Raw XML data, genoma sequence, gene to look for 
#			 ptr to store the translation sequence subset, fuzzyMode flag and ptr to store gen Matched
# Returns: True or False according the Results of the Operation
#
sub get_efetch_translation
{
	my ($rawData, $sequence, $geneString, $ptrTranslationSequence, $fuzzyMode, $genMatched) = @_;
    my $status = ZFALSE;
	my $xmlObject;
	my $xmlData;
	my $gbFeatureArray;
	my $gbQualifierArray;
	my $item;
	my $gbItem;
	my $geneFound = ZFALSE;

	#create XML object
	$xmlObject = new XML::Simple;

	#parse XML data
	$xmlData = $xmlObject->XMLin($rawData);

	# just for debugging purposes
	#print Dumper($xmlData) . "\n";

	if ( defined($xmlData) and defined($geneString) )
	{
		#Not assuming that the needed XML tags are in the fetched XML
		#Getting out the gene intervals	on the XML data					  
		if( defined( $xmlData->{'GBSeq'}->{'GBSeq_feature-table'}->{'GBFeature'} ) )
		{
			$gbFeatureArray = $xmlData->{'GBSeq'}->{'GBSeq_feature-table'}->{'GBFeature'};

			foreach $item (@$gbFeatureArray)
			{
				if ( defined ($item->{'GBFeature_quals'}{'GBQualifier'}) and
					 $item->{'GBFeature_quals'}{'GBQualifier'} =~ /array/i and
					 $item->{'GBFeature_key'} eq "CDS" and
					 $geneFound eq ZFALSE and
					 $status eq ZFALSE )
				{		
					$gbQualifierArray = $item->{'GBFeature_quals'}{'GBQualifier'};

					#Transversing array to look for the array with correct gene
					foreach $gbItem (@$gbQualifierArray)
					{
						#Absolute matching
						if ( not $fuzzyMode  )
						{
							if ( defined ( $gbItem->{'GBQualifier_value'} ) and
#								 $gbItem->{'GBQualifier_value'} eq $geneString   )  	 
								 $gbItem->{'GBQualifier_value'} =~ /^$geneString$/i  ) 
							  {			
									$$genMatched = $gbItem->{'GBQualifier_value'};
									$geneFound = ZTRUE;
							  }
						}
						#Fuzzy matching
						else
						{
							if ( defined ( $gbItem->{'GBQualifier_value'} ) and
								 is_word_present( $gbItem->{'GBQualifier_value'} , $geneString) )  	 
							  {			
									$$genMatched = $gbItem->{'GBQualifier_value'};
									$geneFound = ZTRUE;
							  }
						}

						#Grabbing out the translation value
						if ( defined ( $gbItem->{'GBQualifier_name'} ) and
							 $gbItem->{'GBQualifier_name'} eq "translation" and
							 $geneFound eq ZTRUE )  	 
						  {
								$$ptrTranslationSequence = $gbItem->{'GBQualifier_value'};
								$status = ZTRUE;
						  }
		
					}
					    					 													
				} #end of if 'GBFeature_key'} eq "CDS"

			} #end of foreach $item (@$gbFeatureArray)			
					
		}

	}

	return $status;	
}



#######
# Saving payload to a file using the following syntax
# Parameter: Raw XML data, directory to save and destination filename
# Returns: True or False according the Results of the Operation
#
sub save_file
{
	my ($rawData, $directory_where_to_save, $fileName) = @_;
    my $status = ZFALSE;
	my $workingFileName;

	$workingFileName = "$directory_where_to_save/$fileName";

	if ( open ( XML_OUTPUT , "> $workingFileName" ) )
	{
		print XML_OUTPUT "$rawData\n";
		close XML_OUTPUT;

		$status = ZTRUE;
	}

	return $status;	
}


#######
# Delete file/files located on a given pattern 
# Parameter: pattern of the application's name.
# Returns: status of the operation
#
sub delete_files
{
    my $pattern = shift;
	my $status = ZFALSE;
	my $cmd_to_execute = "";
	my $result = "";

	#remove return character
    chomp($pattern);
							 
	# Safe check to protect ourselves agains rm -rf / scenario
	if ( $pattern !~ /^(\/|\/\s+)$/ )
	{
 	
	 	#Forging out the helper CMD
		$cmd_to_execute = "/usr/bin/env rm -rf $pattern";
		$result = `$cmd_to_execute`;

	    if ( $? eq 0 ) 
		{
			$status = ZTRUE;
		}


	}

	return $status;
}


#######
# Calculate a nucleic acid sequence to amino acid sequence
# Parameter: sequence to translate and ptr to store translation
# Returns: True or False according the Results of the Operation
#
sub calculate_translation
{
	my ($sequence, $ptrTranslation, $errorBuffer) = @_;
    my $status = ZFALSE;
	my @triplets = ();
	my $numberOfTriplets;
	my $codon;
	my $aminoacidFound;
	my $tempTranslation;


	#Start to work only if the length of sqeuences is multiple of 3
	if ( (length($sequence) % TRIPLETS_LENGTH ) eq 0 )
	{
		# get number of triplets
		$numberOfTriplets = length($sequence) / TRIPLETS_LENGTH;
				
		# fill array of triplets
	    @triplets = unpack("a3" x $numberOfTriplets, $sequence);
     
	    # get the translation for each triplet
		foreach $codon (@triplets)
		{
			#look for the aminoacid
			$aminoacidFound	= $rnaCodonTable{$codon};

			if ( defined($aminoacidFound) )
			{
				#decrementing in one the number of triplets found
				$numberOfTriplets = $numberOfTriplets - 1;

				#storing on the working translation if everything is ok
				if ( ($aminoacidFound eq "TER") and ($numberOfTriplets ne 0) )
				{
			   		#Something horrible happens here
					$$errorBuffer = "TER aminoacid in the middle of the sequence!";
					last;
				}
				else
				{  
					if ( $numberOfTriplets ne 0)
					{ 
						#Storing the translation into the temp array
						$tempTranslation = $tempTranslation . $aminoacidFound;
					}
				}

				#Checking the last triplet
				if ( $numberOfTriplets eq 0 )
				{
					#TER is there
					if ($aminoacidFound eq "TER") 
					{
						#storing the translation
						$$ptrTranslation = $tempTranslation;				 

						$status = ZTRUE;
					}
					#TER is not there
					else
					{
						$$errorBuffer = "TER aminoacid is not at the end of the sequence";
						last;
					}
				}
			}
			else
			{
				$$errorBuffer = "Aminoacid was not found for triplet: $codon";
				last;
			}
		}
	}
	else
	{
		$$errorBuffer = "The sequence is not multiple of 3";
	}
	
	return $status;
}





#######
# Generate translation from the raw XML data
# Parameter: Raw XML content, Sequence obtained, gene to look for and translation sequence
# Returns: True or False according the Results of the Operation
#
sub generate_translation_from_xml
{
	my ($rawXMLContent, $sequence, $geneString, $translationSequence) = @_;
	my $geneSequence;
	my $matchedGene;
	my $workingTranslation;
	my $errorBuffer;
    my $status = ZFALSE;

	#trying to obtain the gene sequence substring
	unless ( get_efetch_sequence_with_gene( $rawXMLContent, $sequence, $geneString, \$geneSequence ) )
	{
		fuzzy_get_efetch_sequence_with_gene( $rawXMLContent, $sequence, $geneString, \$geneSequence, \$matchedGene );
	} 
	
	if ( defined($geneSequence) and calculate_translation( $geneSequence, \$workingTranslation, \$errorBuffer )  )
	{ 
		#storing the translation
		$$translationSequence = $workingTranslation;

		$status = ZTRUE;
	}
	else
	{
		#Check that error buffer was not defined in calculate_translation()
		unless ( defined($errorBuffer) )
		{
			$errorBuffer = "Gene sequence was not found!";
		}
	}

	if ( defined($verbose) and defined($errorBuffer) )
	{
		fudepan_print("Calculation of translation failed: $errorBuffer\n");
	}

	return $status;
}






#######
# Check if translations are compatible
# Parameter: Calculated translation and translation obtained from NBCI
# Returns: True or False according the Results of the Operation
#
sub are_translations_compatible
{
	my ($translationCalculated, $lookedTranslationSequence) = @_;
    my $status = ZFALSE;
	my $compatibilityFlag = ZTRUE;
	my @arrayTcalculated = ();
	my @arrayTobtained = ();
	my $iterator = 0;



	#Length are the same?
	if ( length($translationCalculated) eq length($lookedTranslationSequence) )
	{	
		#splitting the provided calculated sequence 
		@arrayTcalculated =	split(//,$translationCalculated);
		@arrayTobtained = split(//,$lookedTranslationSequence);


		while( ($iterator < length($translationCalculated)) and ($compatibilityFlag eq ZTRUE) ) 	
		{
			#Check for compatibility
 			$compatibilityFlag = are_aminoacids_compatible($arrayTcalculated[$iterator],
 													 		$arrayTobtained[$iterator]);
            $iterator++			
		}

		#Store compatibility flag (whatever the results are)
		$status = $compatibilityFlag;
	}

	return $status;
}



#######
# Check if aminoacids are compatible
# Parameter: Calculated translation aminoacid and translation sequence aminoacid obtained from NBCI
# Returns: True or False according the Results of the Operation
#
sub are_aminoacids_compatible
{
	my ($aminoCalculated, $aminoNBCI) = @_;
    my $status = ZFALSE;

	#Aminoacids are the same
	if ( $aminoCalculated eq $aminoNBCI	)
	{
		$status = ZTRUE;
	}

	#Aminoacid are not the same
	else
	{

		#There is no switch() in perl :)
		#Case B
		if ( $aminoCalculated =~ /^B$/i )
		{
			if ( ( $aminoCalculated =~ /^N$/i ) or ( $aminoCalculated =~ /^D$/i ) )
			{
				$status = ZTRUE;
			}
		} 

		#Case Z
		elsif ( $aminoCalculated =~ /^Z$/i )
		{
			if ( ( $aminoCalculated =~ /^Q$/i ) or ( $aminoCalculated =~ /^E$/i ) )
			{
				$status = ZTRUE;
			}
		} 

		#Case J
		elsif ( $aminoCalculated =~ /^J$/i )
		{
			if ( ( $aminoCalculated =~ /^L$/i ) or ( $aminoCalculated =~ /^I$/i ) )
			{
				$status = ZTRUE;
			}
		} 

		#Case X
		elsif ( $aminoCalculated =~ /^X$/i )
		{
			$status = ZTRUE;
		} 
	
		#Default case
		else
		{
			$status = ZFALSE;
		}
		
	}

	return $status;
}





# Get the current working directory
# Parameter: NA
# Returns: Return the current working directory
#
sub get_working_dir
{
    my $status;
    my $working_directory;

    $working_directory = cwd;

    return $working_directory;
}




#######
# Check if a given directory exists
# Parameter: Directory to look for
# Returns: True or False based on the existance
#
sub directory_exists
{
    my $directory = shift;
	my $status = ZFALSE;
    my $retStatus = "";

    #set status to true if directory exists
    if ( -r $directory )
    {
            $status = ZTRUE;
    }

    return $status;
}



#######
# Creates a directory based on the provided argument
# Parameter: Directory to create and permissions for it
# Returns: True or False based on the Directory creation results
#
sub create_set_directory
{
    my ($directoryToCreate, $mode) = @_;
	my $status = ZFALSE;
    my $retStatus = "";
    my $retArrayRef = "";
    my $cmdToBeExecuted;
    my $retLine;
    my $null;
    my $dirMode;

    if ( -d $directoryToCreate )
    {
        #Directory already exists
        #Checking inode directory mode
        ($null,$null,$dirMode) = stat($directoryToCreate);
        #masking out everythin else but directory mode
        $dirMode &= 0777;
        #Saving string literal of mode in octal
        $dirMode = sprintf ("%o", $dirMode);

        #Set directory mode if differs
        if ($dirMode ne $mode)
        {
            if ( chmod(oct($mode), $directoryToCreate) )
            {
                    $status = ZTRUE;
            }
        }
        #Returning true anyway
        else
        {
			$status = ZTRUE;
        }
    }
    else
    {
        #forging command to execute
        $cmdToBeExecuted = "mkdir -m $mode $directoryToCreate";

        #executing cmd and grabbing the output
        my($retStatus, $retArrayRef) = evaluate_cmd("$cmdToBeExecuted");

        #Operation check
        #Check that the retStatus is 0 (Successful completion)
        if($retStatus eq 0 )
        {
			$status = ZTRUE;
        }

    }

    return $status
}



#######
# Check if searchID exists on cache file
# Parameter: Directory, cache file and sequence to look for, and of course, pointer where to save the finding
# Returns: True or False based on the existance
#
sub cache_get_search_id
{
    my ($cacheDir, $cacheFile, $sequenceID, $searchID) = @_;
	my $status = ZFALSE;
	my $workingFile;
	my $line;
	my $foundID;

	$workingFile = "$cacheDir/$cacheFile";

	if( open(CACHE_SEARCH_ID,  "$workingFile") )
	{
		while ($line = <CACHE_SEARCH_ID>)
		{	
			if ( $line =~ /^$sequenceID=/)
			{
				$foundID = $';
				chomp($foundID);								
				$$searchID = $foundID;
				$status = ZTRUE;
				last;
			}
		}
		close(CACHE_SEARCH_ID);	
	}

    return $status;
}

#######
# Update searchID cache file
# Parameter: Directory, cache file where cache file is and sequence and searchId to update
# Returns: True or False based on the existance
#
sub cache_update_search_id
{
	my ($workingCacheDir, $cacheFile, $sequenceID, $searchID) = @_;
	my $status = ZFALSE;
	my $workingFile;

	$workingFile = "$workingCacheDir/$cacheFile";

	if( open(CACHE_SEARCH_ID,  ">> $workingFile") )
	{
		print CACHE_SEARCH_ID "$sequenceID=$searchID\n";
		close(CACHE_SEARCH_ID);	
		$status = ZTRUE;
	}	

    return $status;
}


#######
# Getting Cache saved Eutil XML data
# Parameter: Working dir, type of file to get, Search ID to get and Pointer where to save findings
# Returns: True or False based on the existance
#
sub cache_get_eutil_xml_data
{
	my ($workingCacheDir, $fileType, $searchID, $rawXMLContent) = @_;
	my $status = ZFALSE;
	my $workingFile;
	my $filePayload;

	if ( $fileType =~ /summary/ )
	{
		$workingFile = $workingCacheDir . "/". $searchID ."_summary.xml";
	}
	elsif ( $fileType =~ /efetch/ ) 
	{
		$workingFile = $workingCacheDir . "/". $searchID ."_content.xml";
	}
	else
	{
		#Given type was not supported!
	}

	if ( -e $workingFile )
	{
		if( open(CACHE_FILE_CONTENT,  "$workingFile") )
		{
			# undef $/ to set 'slurp' mode
			undef $/;
			$filePayload = <CACHE_FILE_CONTENT>;
			close(CACHE_FILE_CONTENT);	

			#just a dummy check to ensure that file is not empty
			if ( $filePayload =~ /NCBI GBSeq/ )
			{
				$$rawXMLContent = $filePayload;
				$status = ZTRUE;
			}		
		}	
	}
				
    return $status;
}
